package cz.proks.easyhelpdesk.gwt.activity;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceHistoryMapper;
import com.google.gwt.user.client.ui.AcceptsOneWidget;

import cz.proks.easyhelpdesk.api.model.OAuth2Token;
import cz.proks.easyhelpdesk.api.model.User;
import cz.proks.easyhelpdesk.api.model.base.Id;
import cz.proks.easyhelpdesk.gwt.ClientFactory;
import cz.proks.easyhelpdesk.gwt.Globals;
import cz.proks.easyhelpdesk.gwt.activity.base.BaseActivity;
import cz.proks.easyhelpdesk.gwt.jso.GoogleUser;
import cz.proks.easyhelpdesk.gwt.place.HelpdesksPlace;
import cz.proks.easyhelpdesk.gwt.place.OAuthPlace;
import cz.proks.easyhelpdesk.gwt.place.WelcomePlace;
import cz.proks.easyhelpdesk.gwt.restapi.GoogleRestApi;
import cz.proks.easyhelpdesk.gwt.restapi.OAuth2TokenRestApi;
import cz.proks.easyhelpdesk.gwt.restapi.RestDomainCallback;
import cz.proks.easyhelpdesk.gwt.restapi.RestIdCallback;
import cz.proks.easyhelpdesk.gwt.restapi.UserRestApi;
import cz.proks.easyhelpdesk.gwt.ui.widget.LoadingWidget;
import cz.proks.easyhelpdesk.gwt.utils.CookieUtils;

public class OAuthActivity extends BaseActivity<OAuthPlace> {    
    private enum State { NONE, OAUTH_TOKEN_PROCESSED, EXTERNAL_USER_PROCESSED, MEMBER_PROCESSED }
    
    private String tokenIdStr;
    private OAuth2Token token;
    private JavaScriptObject externalUser;
    private User user;
    
    private AcceptsOneWidget panel;    

    public OAuthActivity(OAuthPlace place, ClientFactory clientFactory, PlaceHistoryMapper placeMapper) {
        super(place, clientFactory, placeMapper);
        this.tokenIdStr = place.getTokenId();
    }

    @Override
    public void start(AcceptsOneWidget panel, EventBus eventBus) {
        this.panel = panel;
        
        this.panel.setWidget(new LoadingWidget());
        processState(State.NONE);
    }
    
    private void processState(State state) {
        switch (state) {
            case NONE:
                processOAuthToken();
                break;
                
            case OAUTH_TOKEN_PROCESSED:
                processExternalUser();
                break;
                
            case EXTERNAL_USER_PROCESSED:
                processMember();
                break;
                
            case MEMBER_PROCESSED:
                processFinish();
                break;
                
            default:
                throw new IllegalStateException();                
        }
    }
    
    private void processOAuthToken() {
        Long tokenId = getTokenId();

        if (tokenId == null) {
            goTo(new WelcomePlace());
            return;
        }

        new OAuth2TokenRestApi().get(tokenId, new RestDomainCallback<OAuth2Token>() {
            @Override
            public void onDomainSuccess(OAuth2Token domain) {
                token = domain;
                processState(State.OAUTH_TOKEN_PROCESSED);
            }
        });
    }
    
    private void processExternalUser() {
        processGoogleUser();
    }

    private void processGoogleUser() {
        new GoogleRestApi().getGoogleUserInfo(token, new RestDomainCallback<GoogleUser>() {
            @Override
            public void onDomainSuccess(GoogleUser domain) {
                externalUser = domain;
                processState(State.EXTERNAL_USER_PROCESSED);
            }
        });        
    }
    
    private void processMember() {
        User aUser = translateFromJso(externalUser);
        
        new UserRestApi().getForProvider(aUser.getProviderId(), new RestDomainCallback<User>() {
            @Override
            public void onDomainSuccess(User domain) {
                user = domain;
                if (user == null)
                    processNewMember();
                else                    
                    processState(State.MEMBER_PROCESSED);                                 
            }
        });        
    }
    
    private void processNewMember() {     
        user = translateFromJso(externalUser);
        
        new UserRestApi().create(user, new RestIdCallback() {
            
            @Override
            public void onIdSuccess(Id id) {
                user.setId(id.getId());
                processState(State.MEMBER_PROCESSED);
            }
        });        
    }  
    
    private void processFinish() {
        CookieUtils.setCookieUser(user);
        Globals.setCurrentUser(user);
        goTo(new HelpdesksPlace());              
    }
        
    private User translateFromJso(JavaScriptObject jsMember) {
        return translateGoogleUser((GoogleUser) jsMember.cast());
    }
       
    private User translateGoogleUser(GoogleUser gUser) {
        if (gUser == null)
            return null;

        User user = new User();

        user.setProviderId(gUser.getId());
        user.setEmail(gUser.getEmail());
        user.setName(gUser.getName());
        user.setSurname(gUser.getSurname());

        return user;
    }
    
    private Long getTokenId() {
        try {
            return Long.valueOf(tokenIdStr);
        } catch (Exception e) {
            return null;
        }
    }

    private void goTo(Place place) {
        getClientFactory().getPlaceController().goTo(place);
    }    
}
